﻿using System;
using System.Collections.Generic;

namespace LOHDemo
{
	// This test does exactly the same as TestInterlacedMemoryAllocationResultsInOutOfMemory
	// IE: It allocates two lists of objects that are interlaced which would cause heavy
	// fragmentation of the large object heap. However in this instance, to prove the point,
	// this test will release both lists proving that in the failing test the reason for 
	// running out of memory is the fragmentation of the heap.
	public class TestInterlacedMemoryAllocationWithFullReleaseDoesNotResultInOutOfMemory : ITest
	{
		public void Execute(IHost host)
		{
			host.StartTest("Test three - filling LOH with interlaced small objects and releasing both lists works");
			host.MemoryUsed("Start of test");
			List<OneMegObject> first = new List<OneMegObject>();
			List<OneMegObject> second = new List<OneMegObject>();

			// Allocate interlaced memory until it runs out
			try
			{
				while (true)
				{
					first.Add(new OneMegObject());
					second.Add(new OneMegObject());
				}
			}
			catch (OutOfMemoryException)
			{
			}

			// LOH is now fill
			host.MemoryUsed("Memory is now full.");

			// Clear both lists
			first.Clear();
			second.Clear();
			first = null;
			second = null;
			GC.Collect(2, GCCollectionMode.Forced);
			host.MemoryUsed("After freeing both lists.");

			// Now we have plenty of free space on the heap, and it's not fragmented
			// let's try to allocate a small 3mb chunk of memory.
			byte[] willfit = new byte[Constants.ThreeMeg];
			host.MemoryUsed("Allocated 3mb");

			// Clean up after ourselves, ensure we've collected the willfit array
			willfit = null;
			GC.Collect(2, GCCollectionMode.Forced);

			host.MemoryUsed("All memory cleaned up");
		}
	}
}
